package com.xctech.yace.factory;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 *
 * 说明：
 *    权重二进制降序生成器
 * 算法说明
 *    例如：给入参（'A', 'B', 'C', 'D'）赋权重（8(2^3),4(2^2),2(2^1),1(2^0)）,
 *    降序生成  1 1 1 1  = 2^0+2^1+2^2+2^3 = 2^4(位数)-1   = 15
 *             1 1 1 0  = 2^0+2^1+2^2+2^3 = 2^4(位数)-2   = 14
 *             ...        ...                             ...
 *             0 0 0 1  = 2^0+2^1+2^2+2^3 = 2^4(位数)-15  = 1
 *             0 0 0 0  = 2^0+2^1+2^2+2^3 = 2^4(位数)-2^4 = 0
 *    将对应的2进制字符串转换成入参，0替换对应的值返回即可
 *
 * 使用方式demo：
 *   WeightBinaryFactory in = WeightBinaryFactory.getInstance('A', 'B', 'C', 'D');
 *   String target;
 *   while((target = in.read()) != null){
 *      System.out.println(target);
 *   }
 */
public class WeightBinaryFactory {


    /**
     * 对象实例
     */
    private static volatile WeightBinaryFactory instance;

    /**
     * 二进制字符串 缓存池
     */
    private static volatile Queue<String> cache = new LinkedList<>();

    /**
     * 可重入锁
     */
    private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();


    public static WeightBinaryFactory getInstance(Object... param){
        if(instance == null){
            instance = new WeightBinaryFactory();
        }
        instance.init(param);
        return instance;
    }

    /**
     * 读
     * @return
     */
    public String read(){
        lock.readLock().lock();
        String poll = cache.poll();
        lock.readLock().unlock();
        return poll;
    }


    private void init(Object... param) {
        lock.writeLock().lock();
        cache.clear();//清空缓存
        lock.writeLock().unlock();

        int bit = param.length;
        Object[] element = null;
        if(param.length != 0){
            element = param;
        }else{
            element = new Object[]{'1','1','1','1','1','1','1','1'};//默认值
            bit = 8;
        }

        StringBuilder sb = null;
        int m;
        int n = 1;
        do {
            sb = new StringBuilder();
            m = (2 << bit) - n;
            String bt = Integer.toBinaryString(1 << bit | m).substring(1);
            char[] cs = bt.toCharArray();
            for(int i = 0;i < cs.length ;i++){
                Object o = cs[i] == '1' ? element[i] : -1;
                sb.append("_");
                sb.append(o);
            }
            lock.writeLock().lock();
            cache.add(sb.toString());
            lock.writeLock().unlock();
            n++;
        }while (m > 0);
    }



}
